import { BlobFile, UploadFile, UploadInput, UploadOutput, UploadServerService, UploadStatus } from "../composition/type";
import { Observable} from "rxjs";
import {humanizeBytes, parseResponseHeaders, secondsToHuman} from "../composition/utils";

export class FFileUploadDefaultService extends UploadServerService {
    /**
     * 2019年3月2日，先假定一个一个传入
     * @param file 
     * @param event 
     */
    upload(files: UploadFile[], event: UploadInput,extendConfig:any): Observable<UploadOutput> {
        let file = files[0];
        return new Observable(observer => {
            const url = event.url ||extendConfig.url|| '';

            const method = event.method || 'POST';
            const data = event.data || {};
            const headers = event.headers || {};

            const xhr = new XMLHttpRequest();
            const time: number = new Date().getTime();
            let progressStartTime: number = (file.progress.data && file.progress.data.startTime) || time;
            let speed = 0;
            let eta: number | null = null;

            xhr.upload.addEventListener('progress', (e: ProgressEvent) => {
                if (e.lengthComputable) {
                    const percentage = Math.round((e.loaded * 100) / e.total);
                    const diff = new Date().getTime() - time;
                    speed = Math.round(e.loaded / diff * 1000);
                    progressStartTime = (file.progress.data && file.progress.data.startTime) || new Date().getTime();
                    eta = Math.ceil((e.total - e.loaded) / speed);

                    file.progress = {
                        status: UploadStatus.Uploading,
                        data: {
                            percentage: percentage,
                            speed: speed,
                            speedHuman: `${humanizeBytes(speed)}/s`,
                            startTime: progressStartTime,
                            endTime: null,
                            eta: eta,
                            etaHuman: secondsToHuman(eta)
                        }
                    };

                    observer.next({ type: 'uploading', files: [file] });
                }
            }, false);

            xhr.upload.addEventListener('error', (e: Event) => {
                observer.error(e);
                observer.complete();
            });

            xhr.onreadystatechange = () => {
                if (xhr.readyState === XMLHttpRequest.DONE) {
                    const speedAverage = Math.round(file.size / (new Date().getTime() - progressStartTime) * 1000);
                    file.progress = {
                        status: UploadStatus.Done,
                        data: {
                            percentage: 100,
                            speed: speedAverage,
                            speedHuman: `${humanizeBytes(speedAverage)}/s`,
                            startTime: progressStartTime,
                            endTime: new Date().getTime(),
                            eta: eta,
                            etaHuman: secondsToHuman(eta || 0)
                        }
                    };

                    file.responseStatus = xhr.status;

                    try {
                        file.response = JSON.parse(xhr.response);
                    } catch (e) {
                        file.response = xhr.response;
                    }

                    file.responseHeaders = parseResponseHeaders(xhr.getAllResponseHeaders());

                    observer.next({ type: 'done', files: [file] });

                    observer.complete();
                }
            };

            xhr.open(method, url, true);
            xhr.withCredentials = event.withCredentials ? true : false;

            try {
                const uploadFile = <BlobFile>file.nativeFile;
                // const uploadIndex = queue.findIndex(outFile => outFile.nativeFile === uploadFile);

                // if (queue[uploadIndex].progress.status === UploadStatus.Cancelled) {
                //     observer.complete();
                // }

                Object.keys(headers).forEach(key => xhr.setRequestHeader(key, headers[key]));

                let bodyToSend: FormData | BlobFile;

                if (event.includeWebKitFormBoundary !== false) {
                    Object.keys(data).forEach(key => file.form.append(key, data[key]));
                    file.form.append(event.fieldName || 'file', uploadFile, uploadFile.name);
                    bodyToSend = file.form;
                } else {
                    bodyToSend = uploadFile;
                }

                //serviceEvents.emit({ type: 'start', file: file });
                xhr.send(bodyToSend);
            } catch (e) {
                observer.complete();
            }

            return () => {
                xhr.abort();
            };
        });
    }
    // 删除附件
    remove(files: UploadFile[], event: UploadInput, extendConfig: any): Observable<UploadOutput> {
        return new Observable(observer => {
            observer.next({ type: 'removed', files: files });
            observer.complete();
        });
    }
}